# -*- coding: utf-8 -*-
from Exceptions.LibraryException import LibraryException
from MediaCollection.Database import Database
from MediaCollection.Video.Episode import Episode

"""
Die Serien-Klasse repräsentiert eine Serie mit allen in der Datenbank 
gespeicherten Attributen. Über ein Objekt dieser Klasse können neue Einträge in
die Datenbank eingefügt werden, im Gegenzug aber auch über die Id des Eintrags 
in der Datenbank die entsprechenden Informationen in das Objekt eingelesen 
werden.

@author: Philipp Dermitzel
@date: 2011-04-08
@version: 1.0.0
@attention: Da ein Großteil der Videodateien nicht über Metadaten verfügt,
    muss zumindest der Name des Filmes über den Dateinamen bzw. den Pfad 
    ableitbar sein. Ohne diese Voraussetzung können die Filmdaten nicht korrekt
    eingelesen werden. Es wird eine der folgende Strukturierungen empfohlen:
        Filme/<Filmname>/Datei.<Dateiendung>
        Filme/<Filmname>.<Dateiendung>
    Bei Serien sollte eine der folgenden Strukturierungen eingehalten werden:
        Serien/<Serienname>/<Staffelnr>/<Episodennummer>.<Dateiendung>
    Ein (gutes) Beispiel wäre der folgende Baum:
        | Filme
        |--| Taxi_Driver
        |--|--| taxidriver.avi
        |--| Star_Wars_IV
        |--|--| sw4.avi
        | Serien
        |--| Breaking_Bad
        |--|--| Season_1
        |--|--|--| 01.avi
        |--|--|--| 02.avi       
        
@author: Philipp Dermitzel
@date: 2011-04-08
@version: 1.0.0
"""
class Series(object):
    """
    ----------------------------------------------------------------------------
    Konstruktor
    ----------------------------------------------------------------------------
    """
    def __init__(self, id = None):
        """
        Speichert alle Informationen des seriess. Ist über C(getData()) abrufbar.
        @type: Dictionary
        """
        self.__seriesData = {
            'id' : None,
            'name' : None,
            'sort' : None,
            'imgPath' : None,
            'imdbId' : None
        }
        
        if id is not None:
            self.__seriesData['id'] = id
            self.getDataFromDb()
        
    """
    ----------------------------------------------------------------------------
    Getter und Setter
    ----------------------------------------------------------------------------
    """
    
    """
    Setzt die Attribute der Serie um diesen später erfolgreich in die 
    Datenbank einfügen zu können. Dafür sollte das übergebene Dictionary
    C(dataDict) alle eben dort beschriebenen Informationen enthalten.    
    @param dataDict: Alle benötigten Informationen zur Serie. Die momentan 
        genutzten Felder sind: id, name, sort, imgPath (Der Pfad zu dem Bild für
        den series und imdbId (die imdb-Id).
    @type dataDict: Dictionary
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Series
    """
    def setData(self, dataDict):
        if 'id' in dataDict:
            self.__seriesData['id'] = dataDict['id']
        if 'name' in dataDict:
            self.__seriesData['name'] = dataDict['name']
        if 'sort' in dataDict:
            self.__seriesData['sort'] = dataDict['sort']
        if 'imgPath' in dataDict:
            self.__seriesData['imgPath'] = dataDict['imgPath']
        if 'imdbId' in dataDict:
            self.__seriesData['imdbId'] = dataDict['imdbId']
        return self
    
    """
    Setzt ein einzelnen Attribut der Serie. Die momentan genutzten Felder sind:
    id, name, sort, imgPath (Der Pfad zu dem Bild für den series und imdbId 
    (die imdb-Id).
    @param key: Der Schlüssel.
    @type key: String
    @param value: Der zu setzende Wert.
    @type value: int oder String
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Series
    """
    def setValue(self, key, value):
        if key == "id":
            self.__seriesData['id'] = value
        elif key == "name":
            self.__seriesData['name'] = value
        elif key == "sort":
            self.__seriesData['sort'] = value
        elif key == "imgPath":
            self.__seriesData['imgPath'] = value
        elif key == "imdbId":
            self.__seriesData['imdbId'] = value
        else: 
            raise LibraryException("\"%s\" ist kein valider Parameter" %key)
        return self
    
    """
    Getter
    @return: Alle Serien-Daten.
    @rtype: Dictionary
    """
    def getData(self):
        return self.__seriesData
    
    """
    Getter.
    @return: Die ID der Serie in der Datenbank.
    @rtype: int
    """
    def getId(self):
        return self.__seriesData['id']
    
    """
    Getter.
    @return: Der Name der Serie.
    @rtype: String
    """
    def getName(self):
        return self.__seriesData['name']
    
    """
    Getter.
    @return: Die Sortierungsschreibweise der Serie.
    @rtype: String
    """
    def getSort(self):
        return self.__seriesData['sort']
    
    """
    Getter.
    @return: Der Pfad zum Bild für diese Serie.
    @rtype: String
    """
    def getImgPath(self):
        return self.__seriesData['imgPath']
     
    """
    Getter.
    @return: Die imdb-Id der Serie.
    @rtype: String
    """
    def getImdbId(self):
        return self.__seriesData['imdbId']
    
    """
    ----------------------------------------------------------------------------
    Methoden der Klasse
    ----------------------------------------------------------------------------
    """
    
    """
    Liest die Serien-Daten aus der Datenbank.
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Series
    """
    def getDataFromDb(self):
        db = Database()
        if self.__seriesData['id'] is None:
            raise LibraryException('Keine ID übergeben')
        
        try: 
            db.select('*', 'Series', {'id':self.__seriesData['id']})
            curseries = db.dbCursor.fetchone()
            self.__seriesData['id'] = curseries[0]
            self.__seriesData['name'] = curseries[1]
            self.__seriesData['sort'] = curseries[2]
            self.__seriesData['imgPath'] = curseries[3]
            self.__seriesData['imdbId'] = curseries[4]
        except: raise LibraryException('Serie nicht vorhanden')        
        return self
    
    """
    Speichert die Serien-Daten in der Datenbank.
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Series
    """   
    def insertIntoDb(self, getData = True):
        if (self.__seriesData['name'] is not None):
            db = Database()
            db.savepoint("sp")
            try: 
                db.insert('Series', {
                    'name'      : self.__seriesData['name'],
                    'sort'      : self.__seriesData['sort'],
                    'imgPath'   : self.__seriesData['imgPath'],
                    'imdbId'      : self.__seriesData['imdbId']
                })
                self.__seriesData['id'] = db.dbCursor.lastrowid
                if getData: self.getDataFromDb()
            except:
                db.rollback("sp")
                raise LibraryException('Konnte Daten nicht einfügen')
        else: raise LibraryException('Nicht alle Daten vorhanden')
        return self
    
    """
    Löscht eine Serie aus der Datenbank. ACHTUNG: Dabei werden auch alle 
    Episoden dieser Serie gelöscht!
    @return: Das 'self'-Objekt (für Chaining)
    @rtype: Series
    """    
    def deleteFromDb(self):
        if self.__seriesData['id'] is None:
            self.getDataFromDb()
        db = Database()        
        try: 
            db.execute("""
                DELETE f, e FROM Film f, Episode e
                 WHERE f.id = e.id 
                   AND e.series = %s
            """ %(self.__seriesData['id']))
            db.delete('Episode', {'series':self.__seriesData['id']})            
            db.delete('Series', {'id':self.__seriesData['id']})
        except: raise LibraryException('Serie nicht vorhanden')
        return self
    
    """
    Holt alle Series aus der Datenbank. Die Sortierungs-Reihenfolge kann über 
    den Parameter orderBy angegeben werden. Dabei kann dieser allen Attributen 
    eines C(Series)-Objektes entsprechen.
    @param orderBy: Sortieren nach x.
    @type orderBy: String
    @return: Ein Array mit allen Serien als Series-Objekte.
    @rtype: Array
    """
    def getAllSeries(self, orderBy = 'name'):
        db = Database()
        try:
            db.select('id', 'Series', {}, "ORDER BY %s" %(orderBy))
            allSeries = db.dbCursor.fetchall()
            seriesArray = []
            for series in allSeries: 
                curSeries = Series(int(series[0]))
                curSeries.getDataFromDb()
                seriesArray.append(curSeries)
            return seriesArray
        except: raise LibraryException('Konnte die Serie nicht auslesen')
        
    """
    Holt alle Episoden einer Serie. Die Standard-Sortierung ist nach Staffel 
    und danach nach Episode.
    @param orderBy: Sortieren nach x.
    @type orderBy: String
    @return: Ein Array mit allen Episoden als Episode-Objekte.
    @rtype: Array
    """
    def getSeriesEpisodes(self, orderBy = 'season AND episode'):
        db = Database()
        try:
            db.select('id', 'Episode', {
                'series' : self.__seriesData['id']
            }, "ORDER BY %s" %(orderBy))
            allEpisodes = db.dbCursor.fetchall()
            episodesArray = []
            for episode in allEpisodes: 
                curEpisode = Episode(int(episode[0]))
                curEpisode.getDataFromDb()
                episodesArray.append(curEpisode)
            return episodesArray
        except: raise LibraryException('Konnte die Episoden nicht auslesen')